import logging
import os
import sys

import subprocess
import time

log = logging.getLogger(__name__)

formatter = logging.basicConfig(level=logging.DEBUG,
                                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                                datefmt='%a, %d %b %Y %H:%M:%S')

basedir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, basedir)

from info_config import db_pt_request_url
from info_config import dbpt_exchange
from info_config import mysql_backup_file_transfer_queue
from info_config import default_bwlimit
from info_config import dbpt_url
from info_config import redis_execute_url
from info_config import lock_timeout

# try:
#     from redis_connect.get_redis_connect import redis_sentinel_instance
# except Exception as e:
#     from redis_connect.get_redis_connect import redis_sentinel_instance

try:
    from ot_utils import RBInfo
    from ot_utils import file_md5_calc
    from ot_utils import info_interactive_with_dbpt
except Exception as e:
    from ot_utils import RBInfo
    from ot_utils import file_md5_calc
    from ot_utils import info_interactive_with_dbpt

    log.exception(str(e))


def get_current_time():
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))


def get_now_time():
    return time.localtime(time.time())


def get_trans_command(**kwargs):
    backup_dir = kwargs.get('backup_dir')
    backup_file_name = kwargs.get('backup_file_name')
    remote_host = kwargs.get('remote_host')
    remote_rsync_module = kwargs.get('remote_rsync_module')
    remote_rsync_port = kwargs.get('remote_rsync_port', 22002)
    rsync_user = kwargs.get('rsync_user', 'dba_rsync')
    rsync_secret = kwargs.get('rsync_secret', 'rsync.secret')
    bwlimit = kwargs.get('bwlimit', default_bwlimit)

    mysql_host = kwargs.get('mysql_host')
    mysql_port = kwargs.get('mysql_port')

    file_to_transfer = "{backup_dir}/{backup_file_name}".format(backup_dir=backup_dir,
                                                                backup_file_name=backup_file_name)
    rsync_command = "rsync -avz --password-file={basedir}/{rsync_secret} --bwlimit={bwlimit} --port={remote_rsync_port} {file_to_transfer} " \
                    "{rsync_user}@{remote_host}::{remote_rsync_module}/{mysql_host}_{mysql_port}/" \
        .format(basedir=basedir,
                file_to_transfer=file_to_transfer,
                rsync_user=rsync_user,
                remote_host=remote_host,
                remote_rsync_module=remote_rsync_module,
                mysql_host=mysql_host,
                mysql_port=mysql_port,
                rsync_secret=rsync_secret,
                remote_rsync_port=remote_rsync_port,
                bwlimit=bwlimit)
    return rsync_command


def run_cmd(cmd, file_trans_info):
    """
    执行命令并发送初始信息给mq
    :param cmd: 执行的备份命令
    :param file_trans_info: 备份文件传输相关信息类
    :return:
    """
    print(cmd)
    p = subprocess.Popen(
        cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    pid = p.pid
    file_trans_info.publish_info_update({'trans_pid': pid})
    file_trans_info.publish_info_update({'transfer_status': 1})
    file_trans_info.backup_startup_publish()
    result = p.stdout.read()
    return_result = result.decode("utf-8", "replace")
    return_code = p.wait()
    return return_code, return_result


def get_trans_startup_message(**kwargs):
    """
    拿传输相关信息
    :param kwargs:
    :return:
    """
    dict_return = {}
    backup_dir = kwargs.get('backup_dir')
    backup_file_name = kwargs.get('backup_file_name')
    remote_host = kwargs.get('remote_host')
    remote_rsync_module = kwargs.get('remote_rsync_module')
    mysql_host = kwargs.get('mysql_host')
    mysql_port = kwargs.get('mysql_port')
    extra_args = kwargs.get('extra_args')
    current_time = get_current_time()
    file_to_transfer = "{backup_dir}/{backup_file_name}".format(backup_dir=backup_dir,
                                                                backup_file_name=backup_file_name)

    file_md5 = file_md5_calc(file_to_transfer)
    dict_return.update({'file_md5': file_md5, 'remote_host': remote_host, 'remote_rsync_module': remote_rsync_module,
                        'mysql_host': mysql_host, 'mysql_port': mysql_port, 'start_time': current_time,
                        'backup_dir': backup_dir, 'backup_file_name': backup_file_name, 'extra_args': extra_args})
    return dict_return


def get_trans_finished_message(**kwargs):
    """
       拿传输相关信息
       :param kwargs:
       :return:
       """
    dict_return = {}
    backup_dir = kwargs.get('backup_dir')
    backup_file_name = kwargs.get('backup_file_name')
    remote_host = kwargs.get('remote_host')
    remote_rsync_module = kwargs.get('remote_rsync_module')
    mysql_host = kwargs.get('mysql_host')
    mysql_port = kwargs.get('mysql_port')
    return_code = kwargs.get('return_code', 0)
    exec_result = kwargs.get('exec_result', 0)
    extra_args = kwargs.get('extra_args', 2)
    current_time = get_current_time()
    file_to_transfer = "{backup_dir}/{backup_file_name}".format(backup_dir=backup_dir,
                                                                backup_file_name=backup_file_name)

    file_md5 = file_md5_calc(file_to_transfer)
    dict_return.update({'file_md5': file_md5, 'remote_host': remote_host, 'remote_rsync_module': remote_rsync_module,
                        'mysql_host': mysql_host, 'mysql_port': mysql_port, 'finished_time': current_time,
                        'transfer_status': 0, 'return_code': return_code, 'backup_dir': backup_dir,
                        'backup_file_name': backup_file_name,
                        'exec_result': exec_result, 'extra_args': extra_args})
    return dict_return


def redis_execute(command, command_argument):
    args_send = {"command": command, "command_argument": command_argument}
    redis_execute_result_from_pt = info_interactive_with_dbpt(db_platform_url=dbpt_url,
                                                              suffix_url=redis_execute_url,
                                                              args_send=args_send,
                                                              method="POST")
    redis_execute_result = redis_execute_result_from_pt.get('msg')
    return redis_execute_result


def set_value_to_get_lock(key_name, lock_value, lock_timeout):
    # suffix_url = "/api_dbpt/execute/redisredis_execute"
    # args_send = {"command": "setnx", "command_argument": "{},{}".format(key_name, lock_value)}
    command_argument = "{},{}".format(key_name, lock_value)
    set_key_result = redis_execute(command="setnx", command_argument=command_argument)
    if set_key_result:
        redis_execute(command="expire", command_argument="{},{}".format(key_name, lock_timeout))
        # redis_sentinel_instance.expire(key_name, lock_timeout)
        return True
    return False


def delete_key_to_unlock(key_name):
    command_argument = "{}".format(key_name)
    redis_execute(command="delete", command_argument=command_argument)
    # redis_sentinel_instance.delete(key_name)


def backup_file_transfer_entry(**kwargs):
    backup_dir = kwargs.get('backup_dir')
    backup_file_name = kwargs.get('backup_file_name')
    remote_host = kwargs.get('remote_host')
    remote_rsync_module = kwargs.get('remote_rsync_module')
    remote_rsync_port = kwargs.get('remote_rsync_port')
    rsync_user = kwargs.get('rsync_user')
    mysql_host = kwargs.get('mysql_host')
    mysql_port = kwargs.get('mysql_port')
    extra_args = kwargs.get('extra_args')

    lock_key_name_base = kwargs.get('lock_key_name_base', 'MYSQL_BACKUP_FILE_TRANSFER_LOCK_')
    key_max = kwargs.get('key_max', 3)
    sleep_time = kwargs.get('sleep_time', 60)
    while True:
        for i in range(1, key_max + 1):
            s = "%03d" % i
            key_name = lock_key_name_base + s
            lock_value = "{}:{}".format(mysql_host, mysql_port)
            transfer_lock_get = set_value_to_get_lock(key_name=key_name, lock_value=lock_value,
                                                      lock_timeout=lock_timeout)
            if transfer_lock_get is True:
                rsync_command = get_trans_command(backup_dir=backup_dir, backup_file_name=backup_file_name,
                                                  remote_host=remote_host,
                                                  remote_rsync_module=remote_rsync_module,
                                                  remote_rsync_port=remote_rsync_port,
                                                  rsync_user=rsync_user, mysql_host=mysql_host, mysql_port=mysql_port)
                transfer_startup_info = get_trans_startup_message(backup_dir=backup_dir,
                                                                  backup_file_name=backup_file_name,
                                                                  remote_host=remote_host,
                                                                  remote_rsync_module=remote_rsync_module,
                                                                  remote_rsync_port=remote_rsync_port,
                                                                  rsync_user=rsync_user,
                                                                  mysql_host=mysql_host,
                                                                  mysql_port=mysql_port,
                                                                  extra_args=extra_args)
                rb_info = RBInfo(rbmq_exchange=dbpt_exchange,
                                 rbmq_queue=mysql_backup_file_transfer_queue)
                rb_info.publish_info_update(transfer_startup_info)
                return_code, exec_result = run_cmd(
                    cmd=rsync_command, file_trans_info=rb_info)
                log.info('return_code : {return_code}'.format(return_code=return_code))
                log.info('exec_result : {exec_result}'.format(exec_result=exec_result))
                transfer_finished_info = get_trans_finished_message(backup_dir=backup_dir,
                                                                    backup_file_name=backup_file_name,
                                                                    remote_host=remote_host,
                                                                    remote_rsync_module=remote_rsync_module,
                                                                    remote_rsync_port=remote_rsync_port,
                                                                    exec_result=exec_result,
                                                                    rsync_user=rsync_user,
                                                                    mysql_host=mysql_host,
                                                                    mysql_port=mysql_port,
                                                                    return_code=return_code,
                                                                    extra_args=extra_args,
                                                                    )
                finished_rbmq = RBInfo(rbmq_exchange=dbpt_exchange,
                                       rbmq_queue=mysql_backup_file_transfer_queue)
                finished_rbmq.publish_info_update(transfer_finished_info)
                finished_rbmq.backup_startup_publish()

                delete_key_to_unlock(key_name)
                return
            else:
                log.info("Can't not get the lock transfer resource , now we sleep a few seconds . ")
                time.sleep(sleep_time)
